#!/usr/bin/env python
#coding:utf-8
from repository import models
from HostSnow_cmdb import settings
import sys,os,datetime,time
from django.utils import timezone
from backend import ssh_interactive

from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
from django.contrib import auth
from django.utils import timezone

def cmd_input(sys_args):

    if len(sys_args) == 0:
        help_display()

    else:
        host_interactive = HostManager()
        if hasattr(host_interactive,sys_args[0]):
            func = getattr(host_interactive,sys_args[0])
            func(sys_args)
        else:
            print("\033[31;1m 无效的参数！\033[0m")
            help_display()

def help_display():
    help_txt = '''
    runserver      run audit interactive interface
    help           show helps
    '''
    print(help_txt)

def print_msg(msg,msg_type,exit=False):
    if msg_type == 'err':
        print("\033[31;1m%s\033[0m" % msg)
    elif msg_type == 'normal':
        print("\033[32;1m%s\033[0m" % msg)
    elif msg_type == 'warning':
        print( "\033[33;1m%s\033[0m" % msg)

    if exit:
        sys.exit()


class  HostManager(object):
     """用户登陆堡垒机后的交互程序"""
     def __init__(self):
         self.cmd_logs = []
         self.models = models    # 导入的所有数据库表对象。
         self.django_settings = settings
         self.user = None


     def runserver(self,argv):
         self.token_auth()       # 首先验证token
         if self.__login_auth(): # 验证堡垒机的 用户登录。
             print (self.django_settings.Welcome_msg)
             self.fetch_hosts()

     def token_auth(self):
        count = 0
        while count < 3:
            token = input("如果没有token，请按回车键, [输入token]:").strip()
            if len(token) == 0: return None
            filter_date = datetime.timedelta(seconds=-300)

            token_list = models.Token.objects.filter(token=token,date__gt=timezone.now() +filter_date)

            if len(token_list) >0:
                if len(token_list) >1:
                    print("发现不匹配的token,我不能让你登录，请联系管理员！")

                else:  #auth correct
                    bind_host_obj = token_list[0].host
                    self.login_user = token_list[0].user
                    self.user_id = token_list[0].user.id

                    print_msg("--- 登录主机 [%s@%s(%s)], 耐心些 --- " %(bind_host_obj.host_user.username,bind_host_obj.host.hostname,bind_host_obj.host.ip_addr),'normal')
                    try:
                        #ssh_interactive.login(self,bind_host_obj)
                        # ssh_interactive.login_raw(self,bind_host_obj)  # 初始化登录。
                        ssh_interactive.login(self, bind_host_obj)
                        print_msg('Bye!','warning',exit=True)

                    except Exception as e:
                        print(e)
                    finally:
                        self.flush_audit_cmd_log(bind_host_obj)
            else:
                count +=1
                print("无效的token，得到 %s 时间尝试！" % (3-count))
        else:
            sys.exit("无效的token，太多的尝试,退出...")


     def __login_auth(self):
       import getpass
       count = 0
       while count < 3:
            user = input("Username:").strip()
            passwd = getpass.getpass("Password:")
            if len(user) == 0 or len(passwd) == 0:
                print("堡垒机账户名或密码不能为空!")
                continue

            user = auth.authenticate(username=user, password=passwd)
            try:
                if user:  # pass authentication
                    print (user)
                    if user.valid_begin_time or  user.valid_end_time:
                        # if timezone.now() > user.valid_begin_time and timezone.now() < user.valid_end_time:
                        self.login_user = user
                        self.user_id = user.id
                        return True
                        # else:
                        #     sys.exit("\033[31;1m 您的帐户已经过期，请联系您的管理员！\033[0m")
                    else:
                        sys.exit("\033[31;1m 您的帐户已经过期，请联系您的管理员！\033[0m")

                else:
                    print("\033[31;1m 无效的用户名或密码\033[0m")
                    count +=1
            except ObjectDoesNotExist as e:
                sys.exit("\033[31;1m 没有 堡垒机的帐户，请登录 http://localhost:8000/admin 创建一个帐户！\033[0m")
       else:
           sys.exit("用户名和密码无效，尝试次数太多，退出...")

     def fetch_hosts(self):
        host_groups = list(self.login_user.host_groups.select_related())

        while True:
            try:
                for index,h_group in enumerate(host_groups):
                    #host_list = models.BindHosts.objects.filter(host_group__id=h_group.id)
                    host_list = h_group.bind_hosts.select_related()
                    print('%s.\t%s [%s]' % (index, h_group.name,len(host_list)))

                print('a.\t全部主机 [%s]' % self.login_user.bind_hosts.select_related().count())

                user_choice = input("\033[32;1m>>:\033[0m").strip()

                if user_choice.isdigit():
                    user_choice = int(user_choice)
                    if user_choice < len(host_groups):
                        while True:
                            #hosts = models.BindHosts.objects.filter(host_group__id=host_groups[user_choice].id )
                            hosts = host_groups[user_choice].bind_hosts.select_related()
                            print ('==host==', hosts)
                            print('===host[0]==',hosts[0])

                            for index,h in enumerate(hosts):
                                print("  %s.\t%s(%s)  %s" %(index,h.host.hostname,h.host.private_ip,h.remote_user))
                            user_choice2 = input("\033[32;1m['b'(back)]>>>:\033[0m").strip()

                            if user_choice2.isdigit():
                                user_choice2 = int(user_choice2)
                                if user_choice2 < len(hosts):
                                    h = hosts[user_choice2]
                                    print('\033[32;1m-----正在连接 [%s] 通过用户: [%s]-----\033[0m' %(h.host.private_ip,h.remote_user))
                                    try:
                                        print('==h==',h)
                                        # ssh_interactive.login_raw(self,h) # 初始化登录。
                                        ssh_interactive.login(self,h)   # promiko 登录.
                                    except Exception as e:
                                        print("\033[31;1m%s\033[0m" %e)
                                    finally:
                                        self.flush_audit_cmd_log(h)
                                else:
                                    print_msg("没有这个选项！", 'err')
                            elif user_choice2 == 'b':
                                break
                    else:
                        print_msg("没有这个选项！", 'err')
                elif user_choice == 'a':  # all hosts show 。
                    hosts = self.login_user.bind_hosts.select_related()
                    while True:
                        for index,h in enumerate(hosts):
                            print("  %s.\t%s(%s)  %s" %(index,h.host.hostname,h.host.private_ip,h.remote_user))
                        user_choice2 = input("\033[32;1m['b'(back)]>>>:\033[0m").strip()

                        if user_choice2.isdigit():
                            user_choice2 = int(user_choice2)
                            if user_choice2 <len(hosts):
                                h= hosts[user_choice2]
                                print('\033[32;1m-----正在连接 [%s] 通过 用户 [%s]-----\033[0m' %(h.host.private_ip,h.remote_user))
                                try:
                                    # ssh_interactive.login_raw(self,h)  # 初始化登录。
                                    ssh_interactive.login(self, h)
                                except Exception as e:
                                    print("\033[31;1m%s\033[0m" %e)
                                finally:
                                    self.flush_audit_cmd_log(h)
                            else:
                                print_msg("没有这个选项!", 'err')
                        elif user_choice2 == 'b':
                            break

                elif user_choice == 'exit':
                    print_msg('Bye!','warning',exit=True)
            except (KeyboardInterrupt,EOFError):
                print_msg("输入'exit'退出！",'err')
            except UnicodeEncodeError as e:
                print_msg("%s, 确保你的终端支持utf8的字符集！" % str(e),'err',exit=True)


     def flush_cmd_input(self,log,host,action_type):
         current_time = timezone.now()
         self.cmd_logs.append([current_time, log, action_type])

         if action_type == 1:  # 新的登录会话，首先创建会话跟踪ID.
             # self.session_track = models.SessionTrack()   旧的
             # self.session_track.save()                    旧的

             self.session_track_obj = models.SessionTrack(user_id=self.user_id, bind_host=host)  #为当前堡垒机用户 创建一个会话跟踪ID记录.
             self.session_track_obj.save()


         if action_type == 2:
             # self.session_track.closed = True
             # self.session_track.save()

             self.flush_audit_cmd_log(host)

             # 更新 ssh 一次连接 到 断开后的会话保持时间 和执行命令的个数.
             count_num = models.AuditLog.objects.filter(session_id=self.session_track_obj.id).count()
             self.session_track_obj.cmd_count = count_num  # 命令数
             self.session_track_obj.closed = True
             self.session_track_obj.stay_time = time.time() - self.session_track_obj.date.timestamp()
             self.session_track_obj.save()

         if len(self.cmd_logs) > 10:
             self.flush_audit_cmd_log(host)


     # @transaction.atomic
     def flush_audit_cmd_log(self,h):
         if len(self.cmd_logs) == 0:
             return

         for log in self.cmd_logs:
             row = models.AuditLog(
                 session=self.session_track_obj,
                 user=self.login_user,
                 host=h,
                 action_type=log[2],
                 cmd=log[1],
                 date=log[0],
             )
             row.save()
         self.cmd_logs = []
         return True









